/* 	Interactive Dominion Interface

Sam Heinith CS362
1/26/2010
*/

#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <string.h>
#include "rngs.h"
#include "interface.h"
#include "dominion.h"

void cardNumToName(int card, char *name){
	switch (card){
	case curse: strcpy(name, "Curse");
		break;
	case estate: strcpy(name, "Estate");
		break;
	case duchy: strcpy(name, "Duchy");
		break;
	case province: strcpy(name, "Province");
		break;
	case copper: strcpy(name, "Copper");
		break;
	case silver: strcpy(name, "Silver");
		break;
	case gold: strcpy(name, "Gold");
		break;
	case adventurer: strcpy(name, "Adventurer");
		break;
	case council_room: strcpy(name, "Council Room");
		break;
	case feast: strcpy(name, "Feast");
		break;
	case gardens: strcpy(name, "Gardens");
		break;
	case mine: strcpy(name, "Mine");
		break;
	case remodel: strcpy(name, "Remodel");
		break;
	case smithy: strcpy(name, "Smithy");
		break;
	case village: strcpy(name, "Village");
		break;
	case baron: strcpy(name, "Baron");
		break;
	case great_hall: strcpy(name, "Great Hall");
		break;
	case minion: strcpy(name, "Minion");
		break;
	case steward: strcpy(name, "Steward");
		break;
	case tribute: strcpy(name, "Tribute");
		break;
	case ambassador: strcpy(name, "Ambassador");
		break;
	case cutpurse: strcpy(name, "Cutpurse");
		break;
	case embargo: strcpy(name, "Embargo");
		break;
	case outpost: strcpy(name, "Outpost");
		break;
	case salvager: strcpy(name, "Salvager");
		break;
	case sea_hag: strcpy(name, "Sea Hag");
		break;
	case treasure_map: strcpy(name, "Treasure Map");
		break;

	default: strcpy(name, "?");
	}

}

int getCardCost(int card) {
	int cost;
	switch (card) {
	case curse: cost = CURSE_COST;
		break;
	case estate: cost = ESTATE_COST;
		break;
	case duchy: cost = DUCHY_COST;
		break;
	case province: cost = PROVINCE_COST;
		break;
	case copper: cost = COPPER_COST;
		break;
	case silver: cost = SILVER_COST;
		break;
	case gold: cost = GOLD_COST;
		break;
	case adventurer: cost = ADVENTURER_COST;
		break;
	case council_room: cost = COUNCIL_ROOM_COST;
		break;
	case feast: cost = FEAST_COST;
		break;
	case gardens: cost = GARDEN_COST;
		break;
	case mine:  cost = MINE_COST;
		break;
	case remodel: cost = REMODEL_COST;
		break;
	case smithy: cost = SMITHY_COST;
		break;
	case village: cost = VILLAGE_COST;
		break;
	case baron: cost = BARON_COST;
		break;
	case great_hall: cost = GREAT_HALL_COST;
		break;
	case minion: cost = MINION_COST;
		break;
	case steward: cost = STEWARD_COST;
		break;
	case tribute: cost = TRIBUTE_COST;
		break;
	case ambassador: cost = AMBASSADOR_COST;
		break;
	case cutpurse: cost = CUTPURSE_COST;
		break;
	case embargo: cost = EMBARGO_COST;
		break;
	case outpost: cost = OUTPOST_COST;
		break;
	case salvager: cost = SALVAGER_COST;
		break;
	case sea_hag: cost = SEA_HAG_COST;
		break;
	case treasure_map: cost = TREASURE_MAP_COST;
		break;
	default: cost = ONETHOUSAND;
	}
	return cost;
}

void printHand(int player, struct gameState *game, FILE *fp) 
{
	assert(fp != NULL);

	int handCount = game->handCount[player];
	int handIndex;

	fprintf(fp, "Player %d's hand:\n", player);
	printf("Player %d's hand:\n", player);

	if (handCount > 0) {
		fprintf(fp, "#  Card\n");
		printf("#  Card\n");
	}
	for (handIndex = 0; handIndex < handCount; handIndex++) {
		int card = game->hand[player][handIndex];
		char name[MAX_STRING_LENGTH];
		cardNumToName(card, name);

		fprintf(fp, "%-2d %-13s\n", handIndex, name);
		printf("%-2d %-13s\n", handIndex, name);
	}

	fprintf(fp, "\n");
	printf("\n");
}



void printDeck(int player, struct gameState *game, FILE *fp) 
{
	assert(fp != NULL);

	int deckCount = game->deckCount[player];
	int deckIndex;

	fprintf(fp, "Player %d's deck: \n", player);
	printf("Player %d's deck: \n", player);

	if (deckCount > 0) {
		fprintf(fp, "#  Card\n");
		printf("#  Card\n");
	}
	for (deckIndex = 0; deckIndex < deckCount; deckIndex++) {
		int card = game->deck[player][deckIndex];
		char name[MAX_STRING_LENGTH];
		cardNumToName(card, name);

		fprintf(fp, "%-2d %-13s\n", deckIndex, name);
		printf("%-2d %-13s\n", deckIndex, name);
	}

	fprintf(fp, "\n");
	printf("\n");
}

void printPlayed(int player, struct gameState *game, FILE *fp) 
{
	assert(fp != NULL);

	int playedCount = game->playedCardCount;
	int playedIndex;

	fprintf(fp, "Player %d's played cards: \n", player);
	printf("Player %d's played cards: \n", player);

	if (playedCount > 0) {
		fprintf(fp, "#  Card\n");
		printf("#  Card\n");
	}
	for (playedIndex = 0; playedIndex < playedCount; playedIndex++) {
		int card = game->playedCards[playedIndex];
		char name[MAX_STRING_LENGTH];
		cardNumToName(card, name);

		fprintf(fp, "%-2d %-13s \n", playedIndex, name);
		printf("%-2d %-13s \n", playedIndex, name);
	}

	fprintf(fp, "\n");
	printf("\n");
}

void printDiscard(int player, struct gameState *game, FILE *fp) 
{
	assert(fp != NULL);

	int discardCount = game->discardCount[player];
	int discardIndex;

	fprintf(fp, "Player %d's discard: \n", player);
	printf("Player %d's discard: \n", player);

	if (discardCount > 0) {
		fprintf(fp, "#  Card\n");
		printf("#  Card\n");
	}
	for (discardIndex = 0; discardIndex < discardCount; discardIndex++) {
		int card = game->discard[player][discardIndex];
		char name[MAX_STRING_LENGTH];
		cardNumToName(card, name);

		fprintf(fp, "%-2d %-13s \n", discardIndex, name);
		printf("%-2d %-13s \n", discardIndex, name);
	}

	fprintf(fp, "\n");
	printf("\n");
}

void printSupply(struct gameState *game, FILE *fp) 
{
	assert(fp != NULL);

	int cardNum, cardCost, cardCount;
	char name[MAX_STRING_LENGTH];

	fprintf(fp, "#   Card          Cost   Copies\n");
	printf("#   Card          Cost   Copies\n");

	for (cardNum = 0; cardNum < NUM_TOTAL_K_CARDS; cardNum++){
		cardCount = game->supplyCount[cardNum];
		if (cardCount == -1) continue;
		cardNumToName(cardNum, name);
		cardCost = getCardCost(cardNum);

		fprintf(fp, "%-2d  %-13s %-5d  %-5d", cardNum, name, cardCost, cardCount);
		fprintf(fp, "\n");
		printf("%-2d  %-13s %-5d  %-5d", cardNum, name, cardCost, cardCount);
		printf("\n");
	}

	fprintf(fp, "\n");
	printf("\n");
}

void printState(struct gameState *game, FILE *fp) 
{
	assert(fp != NULL);

	int numActions = game->numActions;
	int numCoins = game->coins;
	int numBuys = game->numBuys;
	int currentPlayer = game->whoseTurn;
	int phase = game->phase;
	char phaseName[MAX_STRING_LENGTH];
	phaseNumToName(phase, phaseName);

	fprintf(fp, "Player %d:\n%s phase\n%d actions\n%d coins\n%d buys\n\n", currentPlayer, phaseName, numActions, numCoins, numBuys);
	printf("Player %d:\n%s phase\n%d actions\n%d coins\n%d buys\n\n", currentPlayer, phaseName, numActions, numCoins, numBuys);
}

void printScores(struct gameState *game, FILE *fp) 
{
	assert(fp != NULL);

	int playerNum, score[MAX_PLAYERS];
	int numPlayers = game->numPlayers;
	for (playerNum = 0; playerNum < numPlayers; playerNum++) {
		score[playerNum] = scoreFor(playerNum, game);
		fprintf(fp, "Player %d has a score of %d\n", playerNum, score[playerNum]);
		printf("Player %d has a score of %d\n", playerNum, score[playerNum]);
	}
}

void printHelp(void) 
{
	printf("Commands are: \n\
		   	add [Supply Card Number] 			- add any card to your hand (teh hacks)\n\
			buy [Supply Card Number] 			- buy a card at supply position\n\
			end 			      			- end your turn\n\
			init [Number of Players] [Number of Bots] 	- initialize the game\n\
			num 			      			- print number of cards in your hand\n\
			play [Hand Index] [Choice] [Choice] [Choice]	- play a card from your hand\n\
			resign					- end the game showing the current scores\n\
			show 						- show your current hand\n\
			stat 						- show your turn's status\n\
			supp 						- show the supply\n\
			whos 			      			- whos turn\n\
			exit 			      			- exit the interface");
	printf("\n\n");

}

void phaseNumToName(int phase, char *name) 
{
	switch (phase){
	case ACTION_PHASE: strcpy(name, "Action");
		break;
	case BUY_PHASE: strcpy(name, "Buy");
		break;
	case CLEANUP_PHASE: strcpy(name, "Cleanup");
		break;
	}
}

int addCardToHand(int player, int card, struct gameState *game) 
{
	if (card >= adventurer && card < NUM_TOTAL_K_CARDS){
		int handTop = game->handCount[player];
		game->hand[player][handTop] = card;
		game->handCount[player]++;
		return SUCCESS;
	}
	else {
		return FAILURE;
	}

}

void selectKingdomCards(int randomSeed, int kingCards[NUM_K_CARDS]) 
{
	int i, used, card, numSelected = 0;
	SelectStream(1);
	PutSeed((long)randomSeed);


	while (numSelected < NUM_K_CARDS) {
		used = FALSE;
		card = floor(Random() * NUM_TOTAL_K_CARDS);
		if (card < adventurer) continue;
		for (i = 0; i < numSelected; i++) {
			if (kingCards[i] == card) {
				used = TRUE;
				break;
			}
		}
		if (used == TRUE) continue;
		kingCards[numSelected] = card;
		numSelected++;
	}
}

int countHandCoins(int player, struct gameState *game) 
{
	int card, index, coinage = 0;

	for (index = 0; index < game->handCount[player]; index++) {
		card = game->hand[player][index];
		switch (card) {
		case copper: coinage += COPPER_VALUE;
			break;
		case silver: coinage += SILVER_VALUE;
			break;
		case gold: coinage += GOLD_VALUE;
			break;
		}
	}
	return coinage;
}

void bot_buy_phase(int player, struct gameState *game, int coins, int kcards[], FILE *game_fp, FILE *result_fp)
{
	assert(game_fp != NULL);
	assert(result_fp != NULL);

	if (coins >= PROVINCE_COST && supplyCount(province, game) > 0) {
		fprintf(game_fp, "Player %d buys card Province\n\n", player);
		printf("Player %d buys card Province\n\n", player);
		if (buyCard(province, game) != -1) {
			fprintf(result_fp, "Buying Province succeeded.");
		}
		else {
			fprintf(result_fp, "Buying Province failed.");
		}
	}

	int banker = (Random() > 0.5) ? 1 : 0;
	int kcard_bought = 0;
	int card;
	char card_name[MAX_STRING_LENGTH];

	if (banker) {
		if (supplyCount(province, game) == 0 && coins >= DUCHY_COST) {
			fprintf(game_fp, "Player %d buys card Duchy\n\n", player);
			printf("Player %d buys card Duchy\n\n", player);

			if (buyCard(duchy, game) != -1) {
				fprintf(result_fp, "Buying Duchy succeeded.\n");
			}
			else {
				fprintf(result_fp, "Buying Duchy failed.\n");
			}
		}
		else if (coins >= GOLD_COST && supplyCount(gold, game) > 0) {
			fprintf(game_fp, "Player %d buys card Gold\n\n", player);
			printf("Player %d buys card Gold\n\n", player);

			if (buyCard(gold, game) != -1) {
				fprintf(result_fp, "Buying Gold succeeded.");
			}
			else {
				fprintf(result_fp, "Buying gold failed.\n");
			}
		}
		else if (coins >= SILVER_COST && supplyCount(silver, game) > 0) {
			fprintf(game_fp, "Player %d buys card Silver\n\n", player);
			printf("Player %d buys card Silver\n\n", player);

			if (buyCard(silver, game) != -1) {
				fprintf(result_fp, "Buying Silver succeeded.");
			}
			else {
				fprintf(result_fp, "Buying Silver failed.");
			}
		}
		else {
			fprintf(game_fp, "Player %d buys card Copper\n\n", player);
			printf("Player %d buys card Copper\n\n", player);

			if (buyCard(copper, game) != -1) {
				fprintf(result_fp, "Buying copper succedded.\n");
			}
			else {
				fprintf(result_fp, "Buying copper failed.\n");
			}
		}
	}
	else {
		while (!kcard_bought) {
			card = Random() * NUM_K_CARDS;
			if (supplyCount(kcards[card], game) > 0) {
				kcard_bought = TRUE;
				cardNumToName(kcards[card], card_name);
				fprintf(game_fp, "Player %d buys card %s\n\n", player, card_name);
				if (buyCard(kcards[card], game) != -1) {
					fprintf(result_fp, "Attempt to buy card %s succeeded.\n", card_name);
				}
				else {
					fprintf(result_fp, "Attempt to buy card %s failed.\n", card_name);
				}
			}
		}
	}	
}

void bot_action_phase(int player, struct gameState *game, int handPos, FILE *gamefp, FILE *resultfp)
{
	assert(gamefp != NULL);
	assert(resultfp != NULL);

	int choice1, choice2, choice3;
	char card_name[MAX_STRING_LENGTH];

	cardNumToName(game->hand[player][handPos], card_name);

	choice1 = floor(Random() * NUM_K_CARDS);
	choice2 = floor(Random() * NUM_K_CARDS);
	choice3 = floor(Random() * NUM_K_CARDS);

	// These three are known to have bugs.
	if (game->hand[player][handPos] != adventurer &&
		game->hand[player][handPos] != feast &&
		game->hand[player][handPos] != remodel) {
		fprintf(gamefp, "Player %d plays card %s\n\n", player, card_name);
		if (playCard(handPos, choice1, choice2, choice3, game) == -1) {
			fprintf(resultfp, "Attempt to play card %s failed.\n", card_name);
		}
		else {
			fprintf(resultfp, "Attempte to play card %s succeeded.\n", card_name);
		}
	}

	game->numActions--;
}

void executeBotTurn(int player, int *turnNum, struct gameState *game, int kcards[], FILE *game_fp, FILE *result_fp)
{
	assert(game_fp != NULL);
	assert(result_fp != NULL);

	int i, j;
	int handPos;
	int coins = countHandCoins(player, game);

	fprintf(game_fp, "*****************Executing Bot Player %d Turn Number %d*****************\n", player, *turnNum);
	printf("*****************Executing Bot Player %d Turn Number %d*****************\n", player, *turnNum);
	printSupply(game, game_fp);
	printHand(player, game, game_fp);

	for (i = 0; i < game->handCount[player]; i++) {
		for (j = 0; j < NUM_K_CARDS; j++) {
			if (game->hand[player][i] == kcards[j]) {
				handPos = i;
				break;
			}
		}
	}
	
	if (handPos < 501 && game->numActions > 0) {
		if (game->hand[player][handPos] == gardens ||
			game->hand[player][handPos] == minion) {
			game->numActions--;
		}
		
		bot_action_phase(player, game, handPos, game_fp, result_fp);
	}
	
	if (game->numBuys > 0) {
		bot_buy_phase(player, game, coins, kcards, game_fp, result_fp);
	}

	if (player == (game->numPlayers - 1)) {
		(*turnNum)++;
	}
	
	endTurn(game);

	if (!isGameOver(game)) {
		int currentPlayer = whoseTurn(game);
		fprintf(game_fp, "Player %d's turn number %d\n\n", currentPlayer, (*turnNum));
		printf("Player %d's turn number %d\n\n", currentPlayer, (*turnNum));
	}
}
